package general;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class ResourceManager<ResourceClass extends AllocableResource>
{
	private Map<ResourceClass,Integer> resourceCounter = new HashMap<ResourceClass,Integer>();
	private Map<ResourceClass,ResourceClass> allocatedResources = new HashMap<ResourceClass,ResourceClass>();
	private boolean autoDestroyResources;
	
	public ResourceManager(boolean autoDestroyResources)
	{
		this.autoDestroyResources = autoDestroyResources;
	}
	public ResourceClass getAllocatedResource(ResourceClass resource)
	{
		ResourceClass allocatedResource;
		if(!resourceCounter.containsKey(resource))
		{
			resource.allocate();
			resourceCounter.put(resource, 0);
			allocatedResource = resource;
			allocatedResources.put(allocatedResource , allocatedResource);
		}
		else
		{
			allocatedResource = allocatedResources.get(resource);
		}
		int numResources = resourceCounter.get(resource);
		//Increment number of registered shaders
		resourceCounter.put(resource,numResources + 1);
		return allocatedResource;
	}
	public void release(ResourceClass resource)
	{
		assert(resourceCounter.containsValue(resource)) : "Trying to remove shader " + resource.toString() + " which has never been registered.";
		ResourceClass allocatedResource;
		int numResources = resourceCounter.get(resource);
		numResources--;
		if(numResources == 0)
		{
			if(autoDestroyResources)
			{
    			resourceCounter.remove(resource);
    			allocatedResource = allocatedResources.get(resource);
    			allocatedResources.remove(resource);
    			allocatedResource.destroy();
			}
			else
			{
				resourceCounter.put(resource,0);
			}
		}
	}
	public void destroyUnusedResources()
	{
		ResourceClass allocatedResource;
		Set<ResourceClass> deallocatedResources = new HashSet<ResourceClass>();
		for(ResourceClass resource: resourceCounter.keySet())
		{
			if(resourceCounter.get(resource) == 0)
			{
				allocatedResource = allocatedResources.get(resource);
				allocatedResource.destroy();
				deallocatedResources.add(resource);
			}
		}
		for(ResourceClass resource: deallocatedResources)
		{
			resourceCounter.remove(resource);
			allocatedResources.remove(resource);
		}
	}
}
